import { logger } from './log';
import dotenv from 'dotenv';
import TcpClient from './Tcp';
dotenv.config();

/**
 * 设备状态信息接口
 */
interface DeviceStatus {
    deviceId: string;
    gatewayIp: string; // 新增网关IP字段
    lastSeen: number; // 最后一次收到数据的时间戳
    isOnline: boolean; // 当前在线状态
    offlineCount: number; // 掉线次数统计
    firstSeen: number; // 首次接入时间
    battery?: number; // 电池电量
    signal?: number; // 信号强度
}

/**
 * 设备掉线统计事件接口
 */
interface OfflineEvent {
    deviceId: string;
    offlineTime: number;
    offlineCount: number;
    gatewayIp: string;
}

/**
 * 网关有那些设备
 */
interface GatewayIncludesDevice {
    esn: string; // 设备ESN
    deviceId: string; // 设备ID
    status: boolean; // 设备在线状态
    gatewayIp: string; // 网关IP
}

/**
 * 设备状态管理器
 * 负责统计设备掉线次数和管理设备在线状态
 */
class DeviceStatusManager {
    private static instance: DeviceStatusManager | null = null;
    private deviceStatusMap: Map<string, DeviceStatus> = new Map();
    private checkInterval: NodeJS.Timeout | null = null;
    private checkGatewayDeviceInterval: NodeJS.Timeout | null = null;
    private readonly OFFLINE_THRESHOLD = process.env.OFFLINE_THRESHOLD ? parseInt(process.env.OFFLINE_THRESHOLD) : 1800000; // 30分钟无数据视为掉线
    private readonly CHECK_INTERVAL = 30 * 1000; 
    private offlineCallbacks: ((event: OfflineEvent) => void)[] = [];
    private gatewayIncludesDeviceMap: Map<string, Set<GatewayIncludesDevice>> = new Map();
    private readonly GATEWAY_DEVICE_LIMIT = 30; // 每个网关最多只能有30个设备
    private readonly CHECK_GATEWAY_DEVICE_INTERVAL = 30 * 1000; // 检查网关设备数量的间隔时间
    private tcpClient: TcpClient;

    private constructor() {
        this.tcpClient = TcpClient.getInstance();
        this.startStatusCheck();

    }

    // 设置这个网关下的数量
    public addGatewayIncludesDevice(gatewayIp: string, device: GatewayIncludesDevice) {
        if (this.gatewayIncludesDeviceMap.has(gatewayIp)) {
            // logger.warn(`网关 ${gatewayIp} 已存在设备 ${device.deviceId}，更新设备状态`);
            const devices = this.gatewayIncludesDeviceMap.get(gatewayIp);
            if (devices) {
                // 检查设备是否已存在
                const existingDevice = [...devices].find(d => d.esn === device.esn);
                if (existingDevice) {
                    // 更新设备状态
                    existingDevice.status = device.status;
                } else {
                    // 添加新设备
                    console.log('网关添加设备', device)
                    devices.add(device);
                }
            }
            
        } else {
            this.gatewayIncludesDeviceMap.set(gatewayIp, new Set([device]));
        }
    }

    public getGatewayIncludesDevice(gatewayIp: string): Set<GatewayIncludesDevice> {
        return this.gatewayIncludesDeviceMap.get(gatewayIp) || new Set();
    }

    // 获取所有网关下的设备数量
    public getTotalDevices(): Set<GatewayIncludesDevice> {
        let totalDevices = new Set<GatewayIncludesDevice>();
        for (const devices of this.gatewayIncludesDeviceMap.values()) {
            devices.forEach(device => totalDevices.add(device));
        }
        return totalDevices;
    }

    // 删除对应网关下的设备
    public deleteGatewayIncludesDevice(gatewayIp: string, deviceId: string) {
        let devices: Set<GatewayIncludesDevice> | undefined = this.gatewayIncludesDeviceMap.get(gatewayIp);
        if (devices) {
            devices.forEach((device: GatewayIncludesDevice) => {
                if (device.deviceId === String(deviceId)) {
                    devices.delete(device); // 删除设备
                }
            });
            // 重新给网关赋值
            this.gatewayIncludesDeviceMap.set(gatewayIp, devices);
        }
    }

    /**
     * 获取单例实例
     */
    public static getInstance(): DeviceStatusManager {
        if (this.instance === null) {
            this.instance = new DeviceStatusManager();
        }
        return this.instance;
    }

    /**
     * 记录设备数据接收
     * @param deviceId 设备ID
     * @param gatewayIp 网关IP
     */
    public recordDeviceData(deviceId: string, gatewayIp: string,data?: { battery?: number, signal?: number }): void {
        const now = Date.now();
        const existingStatus = this.deviceStatusMap.get(`${gatewayIp}-${deviceId}`);

        if (existingStatus) {
            // 设备之前存在
            const wasOffline = !existingStatus.isOnline;
            existingStatus.lastSeen = now;
            existingStatus.isOnline = true;
            // 更新电池电量和信号强度
            if (data?.battery !== undefined) {
                existingStatus.battery = data.battery;
            }
            if (data?.signal !== undefined) {
                existingStatus.signal = data.signal;
            }
            if (wasOffline) {
                logger.info(`设备 ${deviceId} 重新上线`);
            }
        } else {
            // 检查该网关下的设备数量是否已达到上限（30个）
            const gatewayDeviceCount = this.getTotalDeviceCount(gatewayIp);
            if (gatewayDeviceCount >= this.GATEWAY_DEVICE_LIMIT) {
                logger.warn(`网关 ${gatewayIp} 设备数量已达上限(${this.GATEWAY_DEVICE_LIMIT}个)，拒绝新设备 ${deviceId} 接入`);
                return; // 拒绝接入，不添加到设备管理中
            }

            // 新设备首次接入
            const newStatus: DeviceStatus = {
                deviceId,
                gatewayIp,
                lastSeen: now,
                isOnline: true,
                offlineCount: 0,
                firstSeen: now,
                battery: data?.battery,
                signal: data?.signal,
            };
            this.deviceStatusMap.set(`${gatewayIp}-${deviceId}`, newStatus);
            logger.info(`新设备 ${deviceId} 接入系统，网关 ${gatewayIp} 当前设备数量: ${gatewayDeviceCount + 1}`);
        }
    }

    // 删除对应的网关设备数据（这个是通过时间来删除的）
    public deleteGatewayDeviceData(gatewayIp: string, deviceId: string) {
        const key = `${gatewayIp}-${deviceId}`;
        if (this.deviceStatusMap.has(key)) {
            this.deviceStatusMap.delete(key);
            logger.info(`已删除网关 ${gatewayIp} 下的设备 ${deviceId}`);
        }
    }
    // 查询每一个网关下面设备的数量
    private checkGatewayDeviceCount() {
        this.tcpClient.sockets.forEach((socket, key) => {
            if (socket.isConnected) {
                const gatewayIp = key.split('-')[0];
                this.tcpClient.sendATCommand(gatewayIp, 'AT+DEV?',"queryDevice");  
            }
        })
    }
    /**
     * 开始定期检查设备状态
     */
    private startStatusCheck(): void {
        this.checkInterval = setInterval(() => {
            this.checkDeviceStatus();
        }, this.CHECK_INTERVAL);

        // 开始定期检查网关设备数量
        this.checkGatewayDeviceInterval = setInterval(() => {
            this.checkGatewayDeviceCount();
        }, this.CHECK_GATEWAY_DEVICE_INTERVAL); 
        
        logger.info('设备状态检查器已启动');


    }

    /**
     * 检查所有设备的在线状态
     */
    private checkDeviceStatus(): void {
        const now = Date.now();
        for (const [key, status] of this.deviceStatusMap) {
            const [gatewayIp, deviceId] = key.split('-');
            const timeSinceLastSeen = now - status.lastSeen;
    
            // 如果设备当前在线但超过阈值时间没有数据，标记为掉线
            if (status.isOnline && timeSinceLastSeen > this.OFFLINE_THRESHOLD) {
                status.isOnline = false;
                status.offlineCount++;
                
                const offlineEvent: OfflineEvent = {
                    gatewayIp,
                    deviceId,
                    offlineTime: now,
                    offlineCount: status.offlineCount
                };
                
                logger.warn(`设备 ${deviceId} 掉线，掉线次数: ${status.offlineCount}`);
                
                // 触发掉线事件回调
                this.notifyOfflineEvent(offlineEvent);
                
            }
        }
    }

   /**
     * 通知掉线事件
     */
    private notifyOfflineEvent(event: OfflineEvent): void {
        this.offlineCallbacks.forEach(callback => {
            try {
                callback(event);
            } catch (error) {
                logger.error('掉线事件回调执行失败:', error);
            }
        });
    }

    /**
     * 注册掉线事件监听器
     */
    public onDeviceOffline(callback: (event: OfflineEvent) => void): void {
        this.offlineCallbacks.push(callback);
    }

    /**
     * 获取设备状态
     */
    public getDeviceStatus(deviceId: string, gatewayIp: string): DeviceStatus | undefined {
        return this.deviceStatusMap.get(`${gatewayIp}-${deviceId}`);
    }

    /**
     * 获取所有设备状态
     */
    public getAllDeviceStatus(): DeviceStatus[] {
        return Array.from(this.deviceStatusMap.values());
    }

    /**
     * 获取在线设备数量
     */
        public getOnlineDeviceCount(gatewayIp?: string): number {
        if (gatewayIp) {
            return Array.from(this.deviceStatusMap.values()).filter(status => status.isOnline && status.gatewayIp === gatewayIp).length;
        }
        return Array.from(this.deviceStatusMap.values()).filter(status => status.isOnline).length;
    }

    /**
     * 获取总设备数量
     */
        public getTotalDeviceCount(gatewayIp?: string): number {
        if (gatewayIp) {
            return Array.from(this.deviceStatusMap.values()).filter(status => status.gatewayIp === gatewayIp).length;
        }
        return this.deviceStatusMap.size;
    }

    /**
     * 获取设备统计信息
     */
        public getDeviceStatistics(gatewayIp?: string): {
        totalDevices: number;
        onlineDevices: number;
        offlineDevices: number;
        deviceDetails: DeviceStatus[];
    } {
        const allDevices = gatewayIp ? Array.from(this.deviceStatusMap.values()).filter(device => device.gatewayIp === gatewayIp) : this.getAllDeviceStatus();
        const onlineCount = allDevices.filter(device => device.isOnline).length;
        
        return { 
            totalDevices: allDevices.length,
            onlineDevices: onlineCount,
            offlineDevices: allDevices.length - onlineCount,
            deviceDetails: allDevices
        };
    }

    /**
     * 检查指定网关是否有任何设备数据
     * @param gatewayIp 网关IP地址
     * @returns 是否有设备数据
     */
    public hasDeviceData(gatewayIp: string): boolean {
        return Array.from(this.deviceStatusMap.values()).some(device => device.gatewayIp === gatewayIp);
    }

    /**
     * 获取网关的在线状态（基于是否有设备数据和设备在线状态）
     * @param gatewayIp 网关IP地址
     * @returns 网关是否在线
     */
    public getGatewayOnlineStatus(gatewayIp: string): boolean {
        const gatewayDevices = Array.from(this.deviceStatusMap.values()).filter(device => device.gatewayIp === gatewayIp);
        // 网关在线的条件：有设备数据且至少有一个设备在线
        return gatewayDevices.length > 0 && gatewayDevices.some(device => device.isOnline);
    }

    /**
     * 清理设备状态管理器
     */
    public cleanup(): void {
        if (this.checkInterval) {
            clearInterval(this.checkInterval);
            this.checkInterval = null;
        }
        this.deviceStatusMap.clear();
        this.offlineCallbacks = [];
        logger.info('设备状态管理器已清理');
    }

    /**
     * 移除设备
     */
    public removeDevice(deviceId: string, gatewayIp: string): boolean {
        const removed = this.deviceStatusMap.delete(`${gatewayIp}-${deviceId}`);
        if (removed) {
            logger.info(`设备 ${deviceId} 已从管理器中移除`);
        }
        return removed;
    }

    /**
     * 重置设备掉线计数
     */
    public resetDeviceOfflineCount(deviceId: string, gatewayIp: string): boolean {
        const status = this.deviceStatusMap.get(`${gatewayIp}-${deviceId}`);
        if (status) {
            status.offlineCount = 0;
            logger.info(`设备 ${deviceId} 掉线计数已重置`);
            return true;
        }
        return false;
    }

    /**
     * 根据网关IP移除所有相关设备
     * @param gatewayIp 网关IP
     */
    public removeDevicesByGateway(gatewayIp: string): void {
        let removedCount = 0;
        for (const [key, status] of this.deviceStatusMap.entries()) {
            if (status.gatewayIp === gatewayIp) {
                this.deviceStatusMap.delete(key);
                removedCount++;
            }
        }
        if (removedCount > 0) {
            console.log(`已删除 ${removedCount} 个设备状态记录。`)
           
            logger.info(`已从状态管理器中移除 ${gatewayIp} 的 ${removedCount} 个设备`);
        }
    }
}

export default DeviceStatusManager;
export { DeviceStatus, OfflineEvent, GatewayIncludesDevice };